package com.ohuang.refresh;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Scroller;
import android.widget.Toast;

import androidx.core.view.ViewCompat;
import androidx.core.widget.ListViewCompat;

public class OhRefreshLayout extends ViewGroup implements Refresh {
    private Context context;
    private View topFreshView;
    private View bottomFreshView;
    private View mTarget; // the target of the gesture
    private int topFreshViewH = 300;
    private int bottomFreshViewH = 50;

    private boolean canPullDown = true;
    private boolean canPullUp = true;

    private boolean isPullDown = true;

    private boolean isRefresh = false;
    private Scroller mScroller;


    private int maxPullDownHeight = 500;//最大下拉高度
    private int maxPullUpHeight = 100;//最大上拉高度

    private OnRefreshListener onRefreshListener;


    public boolean isCanPullDown() {
        return canPullDown;
    }

    public void setCanPullDown(boolean canPullDown) {
        this.canPullDown = canPullDown;
    }

    public boolean isCanPullUp() {
        return canPullUp;
    }

    public void setCanPullUp(boolean canPullUp) {
        this.canPullUp = canPullUp;
    }

    public void setMaxPullDownHeight(int height) {
        if (height < 0) {
            height = 0;
        }
        maxPullDownHeight = height;
    }

    public void setMaxPullUpHeight(int height) {
        if (height < 0) {
            height = 0;
        }
        maxPullUpHeight = height;
    }

    public void setTopFreshViewHeight(int height) {
        if (height < 0) {
            height = 0;
        }
        topFreshViewH = height;
        invalidate();
    }

    public void setBottomFreshViewH(int height) {
        if (height < 0) {
            height = 0;
        }
        bottomFreshViewH = height;
        invalidate();
    }

    public void setTopFreshView(View view) {
        if (view != null) {
            removeView(topFreshView);
            topFreshView = view;
            addView(view);
        }
    }

    public void setBottomFreshView(View view) {
        if (view != null) {
            removeView(bottomFreshView);
            bottomFreshView = view;
            addView(view);
        }
    }

    public OhRefreshLayout(Context context) {
        this(context, null);
    }

    public OhRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public OhRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initView();

    }

    public void initView() {

        topFreshView = new ImageRefreshView(context);
        bottomFreshView = LayoutInflater.from(context).inflate(R.layout.refresh_bottom, null, false);
        addView(topFreshView);
        addView(bottomFreshView);
        mScroller = new Scroller(context);

    }


    public OnRefreshListener getOnRefreshListener() {
        return onRefreshListener;
    }

    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        this.onRefreshListener = onRefreshListener;
    }


    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        if (getChildCount() > 3) {
            throw new RuntimeException("OhRefreshLayout 的子组件超过3个");
        }
        mTarget.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
        topFreshView.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(topFreshViewH, MeasureSpec.EXACTLY));
        bottomFreshView.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(bottomFreshViewH, MeasureSpec.EXACTLY));


    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_UP:
                scrollToRefresh();
                break;

        }
        return super.dispatchTouchEvent(ev);
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int width = getMeasuredWidth();
        final int height = getMeasuredHeight();
        if (getChildCount() == 0) {
            return;
        }
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        final View child = mTarget;
        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        final int childWidth = width - getPaddingLeft() - getPaddingRight();
        final int childHeight = height - getPaddingTop() - getPaddingBottom();
        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        int circleWidth = topFreshView.getMeasuredWidth();
        int circleHeight = topFreshView.getMeasuredHeight();
        topFreshView.layout((width / 2 - circleWidth / 2), -topFreshViewH,
                (width / 2 + circleWidth / 2), -topFreshViewH + circleHeight);
        bottomFreshView.layout((width / 2 - circleWidth / 2), b,
                (width / 2 + circleWidth / 2), b + bottomFreshViewH + circleHeight);
    }


    private void ensureTarget() {
        // Don't bother getting the parent height if the parent hasn't been laid
        // out yet.
        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (!child.equals(topFreshView)) {
                    if (!child.equals(bottomFreshView)) {
                        mTarget = child;
                        break;
                    }
                }
            }
        }
    }


    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
    }

    @Override
    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
        boolean canMove = getScrollY() != 0;
        boolean pullDown = dy < 0 && !canChildScrollUp() && canPullDown;
        boolean pullUp = dy > 0 && !canChildScrollDown() && canPullUp;

        if (!isRefresh&&!canMove) {
            if (pullDown) {
                isPullDown = true;
            }
            if (pullUp) {
                isPullDown = false;
            }
        }

        if (pullDown || pullUp || canMove) {
            if (getScrollY() == 0) {
                if (isPullDown) {
                    if (topFreshView instanceof RefreshView) {
                        ((RefreshView) topFreshView).initRefresh();
                    }
                } else {
                    if (bottomFreshView instanceof RefreshView) {
                        ((RefreshView) bottomFreshView).initRefresh();
                    }
                }
            }
            scrollBy(0, dy);
            consumed[1] = dy;
        }
    }

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {

        if (getScrollY() != 0) {
            return true;
        }
        return false;
    }

    private boolean canChildScrollUp() {

        if (mTarget instanceof ListView) {
            return ListViewCompat.canScrollList((ListView) mTarget, -1);
        }
        return mTarget.canScrollVertically(-1);
    }

    private boolean canChildScrollDown() {

        if (mTarget instanceof ListView) {
            return ListViewCompat.canScrollList((ListView) mTarget, 1);
        }
        return mTarget.canScrollVertically(1);
    }


    @Override
    public void scrollTo(int x, int y) {

        if (isPullDown) {
            if (y > 0) {
                y = 0;
            }
            if (y < -maxPullDownHeight) {
                y = -maxPullDownHeight;
            }
        } else {
            if (y < 0) {
                y = 0;
            }
            if (y > maxPullUpHeight) {
                y = maxPullUpHeight;
            }
        }
        if (y != getScrollY()) {
            super.scrollTo(x, y);
        }
    }


    private void scrollToRefresh() {
        int i = getScrollY();
        if (i <= -topFreshViewH) {
            mScroller.startScroll(0, getScrollY(),
                    0, -getScrollY() - topFreshViewH,
                    Math.abs(-getScrollY() - topFreshViewH) * 2);
            topRefresh();
            isRefresh = true;
        } else if (i >= bottomFreshViewH) {
            mScroller.startScroll(0, getScrollY(),
                    0, -getScrollY() + bottomFreshViewH,
                    Math.abs(-getScrollY() + bottomFreshViewH) * 2);
            bottomRefresh();
            isRefresh = true;
        } else {
            mScroller.startScroll(0, getScrollY(),
                    0, -getScrollY(), Math.abs(getScrollY()) * 2);
            isRefresh = false;
        }
        invalidate();

    }

    private void bottomRefresh() {
        if (isRefresh) {
            return;
        }
        if (onRefreshListener != null) {
            onRefreshListener.onBottomRefresh(this);
        }
        if (bottomFreshView instanceof RefreshView) {
            ((RefreshView) bottomFreshView).onRefresh(this);
        }
    }

    private void topRefresh() {
        if (isRefresh) {
            return;
        }
        if (onRefreshListener != null) {
            onRefreshListener.onRefresh(this);
        }
        if (topFreshView instanceof RefreshView) {
            ((RefreshView) topFreshView).onRefresh(this);
        }
    }


    public boolean isRefresh() {
        return isRefresh;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }

    @Override
    public void refreshComplete() {

        if (isPullDown) {
            if (topFreshView instanceof RefreshView) {
                ((RefreshView) topFreshView).refreshComplete();
            }
        } else {
            if (bottomFreshView instanceof RefreshView) {
                ((RefreshView) bottomFreshView).refreshComplete();
            }
        }

        mScroller.startScroll(0, getScrollY(),
                0, -getScrollY(), Math.abs(getScrollY()) * 2);

        isRefresh = false;
        invalidate();
    }

    @Override
    public void release() {
        if (isPullDown) {
            if (topFreshView instanceof RefreshView) {
                ((RefreshView) topFreshView).onRelease(this);
            }
        } else {
            if (bottomFreshView instanceof RefreshView) {
                ((RefreshView) bottomFreshView).onRelease(this);
            }
        }
    }
}
